#include "lib3d/node/Plane.h"
#include <xml/Stream.h>

namespace liba {
namespace lib3d {
namespace node {

const Atom Plane::node_name("Plane");

Plane::Plane(const Atom & name, Node * parent)
	: Node(name, parent)
	, vbCreated(false)
{
	hard::Manager::add_dependent(this);
}

Plane::~Plane()
{
	hard::Manager::remove_dependent(this);
}

void Plane::render_to_list(hard::Hardware* hardware, hard::RenderList* render_list)
{
	hard::VertexBuffer* vb = find_data(hardware);

	if (!vbCreated)
	{
		fillVb(vb);
		vbCreated = true;
	}

	hard::RenderModel render_model;
	render_model.filter_texture = false;
	render_model.world = this->GetGlobalMatrix();
	render_model.vb = vb;
	render_model.primitive_start = 0;
	render_model.primitive_count = 4;
	render_model.vertex_start = 0;
	render_model.vertex_count = 12;
	this->shader.render_to_list(hardware, &render_model.material);
	render_list->models.push_back(render_model);
}

void Plane::fillVb(hard::VertexBuffer* vb)
{
	SimpleArray<float> positions(12*3);
	SimpleArray<float> normals(12*3);
	float * pos_data = positions.data();
	float * nor_data = normals.data();

	float x = 0;
	float dx = 1;
	float y = 0;
	float dy = 1;
	float u = 0;
	float v = 0;
	float du = 1;
	float dv = 1;

	//CCW
	*pos_data++ = x;
	*pos_data++ = y;
	*pos_data++ = 0;

	*pos_data++ = x;
	*pos_data++ = y + dy;
	*pos_data++ = 0;

	*pos_data++ = x + dx;
	*pos_data++ = y;
	*pos_data++ = 0;

	*pos_data++ = x + dx;
	*pos_data++ = y;
	*pos_data++ = 0;

	*pos_data++ = x;
	*pos_data++ = y + dy;
	*pos_data++ = 0;

	*pos_data++ = x + dx;
	*pos_data++ = y + dy;
	*pos_data++ = 0;

	for( int i = 0; i < 6; ++i )
	{
		*nor_data++ = 0;
		*nor_data++ = 0;
		*nor_data++ = 1;
	}

	//CW
	*pos_data++ = x;
	*pos_data++ = y;
	*pos_data++ = 0;

	*pos_data++ = x + dx;
	*pos_data++ = y;
	*pos_data++ = 0;

	*pos_data++ = x;
	*pos_data++ = y + dy;
	*pos_data++ = 0;

	*pos_data++ = x + dx;
	*pos_data++ = y;
	*pos_data++ = 0;

	*pos_data++ = x + dx;
	*pos_data++ = y + dy;
	*pos_data++ = 0;

	*pos_data++ = x;
	*pos_data++ = y + dy;
	*pos_data++ = 0;

	for( int i = 0; i < 6; ++i )
	{
		*nor_data++ = 0;
		*nor_data++ = 0;
		*nor_data++ = -1;
	}

	SimpleArray<float> empty_float;
	SimpleArray<int> empty_int;

	if (!vb->update(positions, normals, empty_float, empty_float, empty_float))
	{
		THROW(Gluck(__FUNCTION__, "vb->update() failed"));
	}
}

void Plane::on_add_hardware(hard::Manager::hardware_type* ha)
{
	hard_vector.push_back(SweetPair(ha, ha->create_vertex_buffer()));
}

bool Plane::on_node( xml::Provider * prov, const std::string & name )
{
	if (name == "Shader")
		return prov->parse_object(&this->shader);

	return Node::on_node(prov, name);
}

} // namespace node
} // namespace lib3d
} // namespace liba